package cn.edu.lzzy.mypractices.service;

import cn.edu.lzzy.mypractices.constant.Messages;
import cn.edu.lzzy.mypractices.entity.*;
import cn.edu.lzzy.mypractices.repository.*;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class ResultServiceImpl implements ResultService {

    private final ResultRepository resultRepository;
    private final QuestionRepository questionRepository;
    private final UserRepository userRepository;
    private final ChapterRepository chapterRepository;

    public ResultServiceImpl(ResultRepository resultRepository,
                             QuestionRepository questionRepository,
                             UserRepository userRepository,
                             ChapterRepository chapterRepository) {
        this.resultRepository = resultRepository;
        this.questionRepository = questionRepository;
        this.userRepository = userRepository;
        this.chapterRepository = chapterRepository;
    }

    @Override
    public List<Result> getAllByQuestionId(UUID questionId) {
        return resultRepository.findAllByQuestionId(questionId);
    }

    @Override
    public Result answerQuestion(Result result) {
        return resultRepository.save(result);
    }

    @Override
    public int getScore(UUID userId, UUID chapterId) {
        User u = userRepository.findById(userId).orElse(null);
        Chapter c = chapterRepository.findById(chapterId).orElse(null);

        if (u != null && c != null) {
            List<Result> allResults = resultRepository.findAllByStudentId(u.getId()).stream().filter(r -> r.getQuestion().getChapter().getId() == chapterId).collect(Collectors.toList());
            if (allResults.size() > 0 && c.getQuestions().size() > 0) {
                int scorePerQuestion = 100 / c.getQuestions().size();

                int score = 0;

                for(Result r : allResults) {
                    int i = isRightAnswer(r.getQuestion(), r);
                    if (i == Result.CORRECT || i == Result.LES_SELECTION || i == Result.OVR_SELECTION) {
                        score += i == Result.LES_SELECTION || i == Result.OVR_SELECTION ? scorePerQuestion / 2 : scorePerQuestion;
                    }
                }

                return score;
            }
        }

        return -1;
    }

    @Override
    public List<User> getAllAnsweredRightUsers(UUID questionId) {
        Question question = questionRepository.findById(questionId).orElse(null);
        List<User> right = new ArrayList<>();

        if (question != null) {
            List<Result> allResults = resultRepository.findAllByQuestionId(questionId);
            for(Result r : allResults) {
                if (isRightAnswer(r.getQuestion(), r) == Result.CORRECT) {
                    right.add(r.getStudent());
                }
            }
        }

        return right;
    }

    @Override
    public int getAnswerResult(UUID userId, UUID questionId) {
        Result result = resultRepository.findByStudentIdAndQuestionId(userId, questionId);
        if (result != null) {
            return isRightAnswer(result.getQuestion(), result);
        }
        return Result.NOT_DONE;
    }
    public int isRightAnswer(Question q, Result r) {
        if (q.getType() == Question.SINGLE_CHOICE || q.getType() == Question.JUDGEMENT) { // 单选 | 判断
            if (r.getOptions().get(0).isAnswer()) {
                return Result.CORRECT;
            }
        } else { // 多选
            List<Option> rightAnswers = q.getOptions().stream().filter(Option::isAnswer).collect(Collectors.toList());
            int match = 0;
            for (Option o : rightAnswers) {
                if (r.getOptions().contains(o)) {
                    match++;
                    break;
                }
            }
            if (match > 0) {
                if (match == rightAnswers.size()) {
                    return Result.CORRECT;
                } else if (r.getOptions().size() > rightAnswers.size()) {
                    return Result.OVR_SELECTION;
                } else {
                    return Result.LES_SELECTION;
                }
            }
        }

        return Result.MIS_SELECTION;
    }
}
